package com.sxyc.common;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 本地缓存类
 * @author WangQian
 *
 */
public class LocalCache {

	private static Map<String, Cache> LocalCache = new ConcurrentHashMap<String, Cache>();// 存储缓存对象
	private static List<String> tempList = new ArrayList<String>(10);// 存储需要监控过期时间的缓存对象的键
	private static Thread timeoutTimerThread = new Thread(new TimeoutTimerThread());// 定期清理过期缓存对象

	/**
	 * 判断是否包含缓存
	 * 
	 * @param key
	 * @return
	 */
	public static boolean containCache(String key) {
		return containCache(null, key);
	}

	/**
	 * 判断是否包含缓存
	 * 
	 * @param namespace
	 *            命名空间
	 * @param nkey
	 * @return
	 */
	public static boolean containCache(String namespace, String nkey) {
		String key = namespace + "_$_" + nkey;
		return LocalCache.containsKey(key);
	}

	/**
	 * 读取缓存数据
	 * 
	 * @param key
	 * @return
	 */
	public static final Object getCache(String key) {
		return getCache(null, key);
	}

	/**
	 * 读取缓存数据
	 * 
	 * @param namespace
	 *            命名空间
	 * @param nkey
	 * @return
	 */
	public static final Object getCache(String namespace, String nkey) {
		Cache cache = getCacheInfo(namespace, nkey);
		return cache == null ? null : cache.getValue();
	}

	/**
	 * 读取缓存对象
	 * 
	 * @param key
	 * @return
	 */
	public static final Cache getCacheInfo(String key) {
		return getCacheInfo(null, key);
	}

	/**
	 * 读取缓存对象
	 * 
	 * @param namespace
	 *            命名空间
	 * @param nkey
	 * @return
	 */
	public static final Cache getCacheInfo(String namespace, String nkey) {
		if (containCache(namespace, nkey)) {
			String key = namespace + "_$_" + nkey;
			Cache cache = LocalCache.get(key);
			if (cacheExpired(cache)) { // 调用判断是否终止方法
				cache.setExpired(true);
			}
			return cache;
		}
		return null;
	}

	/**
	 * 增加缓存数据
	 * 
	 * @param key
	 * @param value
	 */
	public static void putCache(String key, Object value) {
		putCache(null, key, value);// 默认永久保存
	}

	/**
	 * 增加缓存数据
	 * 
	 * @param namespace
	 *            命名空间
	 * @param nkey
	 * @param value
	 */
	public static void putCache(String namespace, String nkey, Object value) {
		Cache cache = new Cache();
		cache.setNamespace(namespace);
		cache.setKey(nkey);
		cache.setValue(value);
		cache.setExpireTime(0);// 默认永久保存
		cache.setExpired(false);

		String key = namespace + "_$_" + nkey;
		LocalCache.put(key, cache);
	}

	/**
	 * 增加缓存数据，并设置过期时间
	 * 
	 * @param key
	 * @param value
	 * @param timeout
	 *            过期时间，毫秒单位
	 */
	public static void putCacheInfo(String key, Object value, long timeout) {
		putCacheInfo(null, key, value, timeout);
	}

	/**
	 * 增加缓存数据，并设置过期时间
	 * 
	 * @param namespace
	 *            命名空间
	 * @param nkey
	 * @param value
	 * @param timeout
	 *            过期时间，毫秒单位
	 */
	public static void putCacheInfo(String namespace, String nkey, Object value, long timeout) {
		Cache cache = new Cache();
		cache.setNamespace(namespace);
		cache.setKey(nkey);
		cache.setValue(value);
		cache.setExpireTime((timeout + System.currentTimeMillis()));
		cache.setExpired(false);

		String key = namespace + "_$_" + nkey;
		LocalCache.put(key, cache);

		tempList.add(key); // 加入监控过期时间列表
		if (!timeoutTimerThread.isAlive()) {
			timeoutTimerThread.start();// 启动线程
		}
	}

	/**
	 * 删除缓存
	 * 
	 * @param key
	 */
	public static void removeCache(String key) {
		removeCache(null, key);
	}

	/**
	 * 删除缓存
	 * 
	 * @param namespace
	 *            命名空间
	 * @param nkey
	 */
	public static void removeCache(String namespace, String nkey) {
		String key = namespace + "_$_" + nkey;
		LocalCache.remove(key);
	}

	/**
	 * 判断缓存是否过期
	 * 
	 * @param cache
	 * @return
	 */
	private static boolean cacheExpired(Cache cache) {
		if (null == cache) { // 传入的缓存不存在
			return false;
		}
		long nowDt = System.currentTimeMillis(); // 系统当前的毫秒数
		long cacheDt = cache.getExpireTime(); // 缓存内的过期毫秒数
		if (cacheDt <= 0 || cacheDt >= nowDt) { // 过期时间小于等于零时,或者过期时间大于当前时间时，则为FALSE
			return false;
		} else { // 大于过期时间 即过期
			return true;
		}
	}

	/**
	 * 定期清理过期缓存对象
	 */
	private static class TimeoutTimerThread implements Runnable {
		public void run() {
			while (true) {
				try {
					if (tempList != null && tempList.size() > 0) {
						Iterator it = tempList.iterator();
						while (it.hasNext()) {
							String key = (String) it.next();
							Cache cache = LocalCache.get(key);
							if (cacheExpired(cache)) { // 调用判断是否终止方法
								String namespace = cache.getNamespace();
								String nkey = cache.getKey();
								removeCache(namespace, nkey);// 清除过期缓存对象
								it.remove();
								System.out.println("清除命名空间:" + namespace + "，过期缓存对象:" + nkey);
							}
						}
					} else {
						break;// 没有监控对象，中断线程
					}
					Thread.sleep(1000);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 缓存对象
	 */
	public static class Cache implements java.io.Serializable {

		private static final long serialVersionUID = -8843999583819980418L;

		private String namespace;// 命名空间
		private String key;// 缓存ID
		private Object value;// 缓存数据
		private long expireTime;// 失效时间
		private boolean expired; // 是否终止

		public Cache() {
			super();
		}

		public Cache(String key, Object value, long expireTime, boolean expired) {
			super();
			this.key = key;
			this.value = value;
			this.expireTime = expireTime;
			this.expired = expired;
		}

		public String getNamespace() {
			return namespace;
		}

		public void setNamespace(String namespace) {
			this.namespace = namespace;
		}

		public String getKey() {
			return key;
		}

		public void setKey(String key) {
			this.key = key;
		}

		public Object getValue() {
			return value;
		}

		public void setValue(Object value) {
			this.value = value;
		}

		public long getExpireTime() {
			return expireTime;
		}

		public void setExpireTime(long expireTime) {
			this.expireTime = expireTime;
		}

		public boolean isExpired() {
			return expired;
		}

		public void setExpired(boolean expired) {
			this.expired = expired;
		}
	}

	public static void main(String[] args) {
		try {
			putCacheInfo("1", "1", args, 5000);
			putCache("2", args);
			System.out.println(getCache("2"));
			Thread.sleep(5000);
			putCacheInfo("1", "3", "2222", 5000);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
